import $API from '@/api'
import CachedVariableManager from '@/store/_cachedVariableManager'
import { AuthenticationTokens, UserInfo } from '@/types/response/user'
import useGetLoginInfo from '@/hooks/useGetLoginInfo'
import { WeixinLoginParam } from '@/types/param/user'

import type { AddressBookResponse } from '@/types/response/address-book'
import { throttle } from '@/utils/throttle'
import Event from '@/store/_event'
import LocationStore from './position'

const { getCode, getEncryptedDataAndIv } = useGetLoginInfo()
export default class UserStore {
  public tokens = new CachedVariableManager<AuthenticationTokens>('AuthenticationTokens')
  // 个人信息: 长缓存，必要时要进行刷新或说跟随重新登录进行刷新（在登录时会刷新 、 修改基本信息后）
  public userInfo = new CachedVariableManager<UserInfo>('UserInfo')
  // 节流方式获取用户基本信息
  public throttleUpdateUserInfo = throttle(() => this.updateUserInfo.apply(this), 2000)
  // 用于用户选择地址后，确认页接收
  public userChooseAddressEvent = new Event<AddressBookResponse>()
  // 用户位置信息
  public positionStore = new LocationStore()
  // 用户搜索历史
  public searchHistory = new CachedVariableManager<string[]>('USER-SEARCH-HISTORY')
  constructor() {
    // 延时检查,用户基本信息的有效性，无效去请求
    setTimeout(() => {
      this.userInfo.getValue() == null && this.throttleUpdateUserInfo()
    }, 460)
  }

  // 更新用户基本信息
  public async updateUserInfo() {
    const result = await $API.user.getUserInfo()
    if (!result.success) throw new Error('更新用户基本信息缓存失败！')
    this.userInfo.setValue(result.data)
  }
  // 当token无效或过期时，通过刷新或老用户登录来获取token
  public async getTokenOnInvalidUseRefreshOrLogin() {
    if ((await this.getTokenOnExpireUseRefresh()) == null) {
      // 获取不到token，则登录刷新token
      await this.loginSetToken()
    }
    return this.tokens.getValue()?.access_token
  }

  // 当token过期时，通过刷新来获取token
  public async getTokenOnExpireUseRefresh() {
    const tokensValue = this.tokens.getValue()
    // 如果token过期，则尝试刷新
    console.log('==>', tokensValue, AuthenticationTokens.isExpired(tokensValue?.refresh_token_expire_in))
    if (tokensValue != null && (await this.refreshToken())) {
      console.log('刷新了token:', this.tokens.getValue()?.access_token)
      return this.tokens.getValue()?.access_token
    }
    console.log('需要登录，无法获取token')
    // 实在获取不了，则重新登录返回null，让调用者处理
    return null
  }

  public async refreshToken(): Promise<boolean> {
    console.log('refreshToken')
    const tokensValue = this.tokens.getValue()
    if (tokensValue == null || tokensValue.refresh_token == null) return false
    const result = await $API.user.refreshToken(tokensValue.refresh_token)
    console.log('请求刷新！！')
    if (!result.success) {
      // 清理掉本地已无效的token信息
      this.tokens.clearValue()
      return false
    }
    this.tokens.setValue(result.data, result.data.refresh_token_expire_in)
    return true
  }
  public async loginSetToken(): Promise<boolean> {
    const [code, { encryptedData, iv }] = await Promise.all([getCode(), getEncryptedDataAndIv()])
    const result = await $API.user.loginForWeixin(new WeixinLoginParam(code, encryptedData, iv))
    if (result.success) {
      this.tokens.setValue(result.data, result.data.refresh_token_expire_in)
      // 刷新用户基本信息
      this.throttleUpdateUserInfo()
      return true
    }
    return false
  }
  // // 定位获取用户位置(更新userPosition)
  // public async requestLocation(): Promise<LngLatDetail> {
  //   console.log('定位获取用户位置')

  //   let positionValueForCache = this.userPosition.getValue()
  //   if (positionValueForCache == null) {
  //     this.userPosition.setValue((positionValueForCache = await requestDetail()))
  //   }
  //   return positionValueForCache
  // }
  // // 用户手动选择位置(更新userPosition)
  // public selectAddress(): Promise<LngLatDetail> {
  //   return new Promise<LngLatDetail>((resolve, reject) => {
  //     uni.chooseLocation({
  //       success: async (res) => {
  //         console.log('选择的地址', res)
  //         // (!!为什么是请求到lat\lng且code才请求数据，因为更快!!)
  //         const result = await requestDetail({ latitude: res.latitude, longitude: res.longitude })
  //         this.userPosition.setValue({ ...result, addressLabel: res.name || result.detailAddress })
  //         resolve(result)
  //       }
  //     })
  //   })
  // }
}
